/** 注释
 * @Name globalConfirm;
 * @Author FiveXu
 * @Description globalConfirm
 * @Date 2021-07-16 09:30
 */

import { createApp } from 'vue'
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
import confirmVue, { ConfirmProps } from '@/base/directive/confirm/confirm.vue'
import { Emitter } from 'mitt'
import { ComponentPublicInstance } from '@vue/runtime-core'
import { getZIndex } from '@/base/hooks'

interface ConfirmInstance extends ComponentPublicInstance {
  setCancelLoading?: (val: boolean) => void;
  setDefineLoading?: (val: boolean) => void;
  cancelText?: string;
  confirmMitt?: Emitter;
  closeConfirm?: () => void;
}

interface GlobalConfirmProps extends ConfirmProps {
  beforeClose: (active: 'define' | 'cancel' | 'close', app: { setCancelLoading: (val: boolean) => void; setDefineLoading: (val: boolean) => void; }, cb: () => void) => void
}

type Props = Partial<GlobalConfirmProps>

class GlobalConfirm {
  private readonly props: Partial<GlobalConfirmProps>
  private confirmDom: HTMLElement | undefined
  private confirmApp: ConfirmInstance | undefined
  private confirmPromise: { resolve: (value: string) => void, reject: (value: string) => void } | undefined

  constructor (content: string | Props, title?: string | Props, props?: Props) {
    if (typeof content === 'object') {
      this.props = content
    } else if (typeof title === 'object') {
      this.props = Object.assign({ content }, title)
    } else {
      this.props = Object.assign({ title }, { content }, props)
    }
  }

  // 初始化样式
  private initStyle = (): HTMLElement => {
    const dom: HTMLElement = document.createElement('div')
    dom.style.position = 'fixed'
    dom.style.zIndex = String(getZIndex())
    return dom
  }

  // 初始化消息VUE
  public initConfirm (): Promise<string> {
    this.confirmDom = this.initStyle()
    document.body.appendChild(this.confirmDom)
    const props = { ...this.props }
    delete props.beforeClose
    this.confirmApp = createApp(confirmVue, props).mount(this.confirmDom)
    if (this.confirmApp?.confirmMitt) {
      this.confirmApp.confirmMitt.on('close', this.handleConfirmClose.bind(this))
      this.confirmApp.confirmMitt.on('define', this.handleConfirmDefine.bind(this))
    }
    this.confirmPromise = Promise
    return new Promise((resolve, reject) => {
      this.confirmPromise = {
        resolve,
        reject
      }
    })
  }

  // 处理关闭前事件
  private handleBeforeClose (val: 'close' | 'cancel' | 'define'): void {
    if (!this.props.beforeClose) return
    const app = {
      setCancelLoading: (val: boolean) => {
        this.confirmApp?.setCancelLoading && this.confirmApp.setCancelLoading(val)
      },
      setDefineLoading: (val: boolean) => {
        this.confirmApp?.setDefineLoading && this.confirmApp.setDefineLoading(val)
      }
    }
    this.props.beforeClose(val, app, () => {
      if (this.confirmPromise) {
        val === 'define' ? this.confirmPromise.resolve(val) : this.confirmPromise.reject(val)
      }
      this.close()
    })
  }

  // 处理关闭事件
  private handleConfirmClose (val: 'close' | 'cancel' | undefined): void {
    if (!val) return
    if (this.props.beforeClose) {
      this.handleBeforeClose(val)
      return
    }
    this.confirmPromise && this.confirmPromise.reject(val)
    this.close()
  }

  // 处理确认事件
  private handleConfirmDefine (val: 'define' | undefined): void {
    if (!val) return
    if (this.props.beforeClose) {
      this.handleBeforeClose(val)
      return
    }
    this.confirmPromise && this.confirmPromise.resolve(val)
    this.close()
  }

  // 关闭 并使用关闭动画
  private close (): void {
    this.confirmApp?.closeConfirm && this.confirmApp.closeConfirm()
    setTimeout(() => {
      this.confirmDom && this.confirmDom.remove()
    }, 150)
  }
}

export const Confirm = (content: string | Props, title?: string | Props, props?: Props): Promise<string> => {
  return new GlobalConfirm(content, title, props).initConfirm()
}
